package com.xpec.c4.service.contexts;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.ms.service.module.account.message.SSessionCloseNotify;
import com.ms.service.module.broadcastlistener.LoginLogoutListener;
import com.ms.service.module.processer.BasiceServiceProcesser;
import com.xpec.c4.game.utility.GUID;
import com.xpec.c4.game.utility.GameUtility;
import com.xpec.c4.message.ConstantCode;
import com.xpec.c4.message.ContextStatus;
import com.xpec.c4.message.MessageTypes;
import com.xpec.c4.service.common.ServiceInfo;
import com.xpec.c4.service.group.transportlayer.GroupMessage;
import com.xpec.c4.service.h5common.H5ServiceInfo;
import com.xpec.c4.service.message.MessageAction;
import com.xpec.c4.service.module.BasicServiceModule;
import com.xpec.c4.service.module.ModuleName;
import com.xpec.c4.service.module.ServerProperties;
import com.xpec.c4.service.module.common.PlayerCommonInfoManager;
import com.xpec.c4.service.server.CloseType;
//TODO:之後要將跟IocContainer有關的東西都拿掉 ， 這動作原先是要用來可以預讀之前做過的動作，但是因為太浪費記憶體空間所以要拿掉

/**
 * 整个的上下文容器
 * 
 * @author lipeilin
 * 
 */
public class Contexts {
	
	public final static Object NOT_FOUND = new Object();

	/**
	 * 
	 */
	private static final String USER_ID_KEY = "@userID@";

	/**
	 * 
	 */
	private static final String SESSION_ID_KEY = "@sessionID@";

	/**
	 * 
	 */
	private static final Log log = LogFactory.getLog(Contexts.class);

	/**
	 * 应用层上下文
	 */
	static final ApplicationContext applicationContext = new ApplicationContext();

//	/**
//	 * 应用层上下文
//	 */
//	static final GroupContext groupContext = new GroupContext();

	/**
	 * 会话层上下文
	 */
	static final Map<GUID, SessionContext> sessionContexts = new ConcurrentHashMap<GUID, SessionContext>(5000);

	/**
	 * 对话层上下文
	 */
//	static final Map<String, UserContext> userContexts = new ConcurrentHashMap<String, UserContext>(
//			5000);

	/**
	 * 事件层上下文
	 */
	static final ThreadLocal<EventContext> eventContext = new ThreadLocal<EventContext>();
	
	/**
	 * 可獲取當前的Module
	 */
	private static ThreadLocal<BasicServiceModule> curModule = new ThreadLocal<BasicServiceModule>();
	

	/**
	 * SESSIONID与GUID的对应表
	 */
	//static final IShareMap<String, String> userSessionID = ServerGroup
	//		.getDataManager().getShareMap("playerSessionID");

	/**
	 * GUID与SESSIONID的对应表本地缓存表
	 */
	static final HashMap<GUID, GUID> userSessionId = new HashMap<GUID, GUID>(5000);

	/**
	 * SESSIONID与GUID的对应表本地缓存表
	 */
	static final HashMap<GUID, GUID> sessionUserId = new HashMap<GUID, GUID>(5000);
	
	/**
	 * 监听器
	 */
	static final HashSet<ContextsListener> listeners = new HashSet<ContextsListener>();

	static {
		eventContext.set(new EventContext());
	}
	
	/**
	 * 构造, 强迫要给一个Module 
	 * @param module
	 */
	@SuppressWarnings("static-access")
	public Contexts(BasicServiceModule module){
		
		if(this.curModule == null){
			this.curModule = new ThreadLocal<BasicServiceModule>();			
		}
		this.curModule.set(module);
	}
	
	/**
	 * 
	 * @return
	 */
	public static BasicServiceModule getModule(){
		return curModule.get();
	}
	
	public static BasiceServiceProcesser getProcesser()
	{
		return curModule.get().getBasicprocesser();
	}

	/**
	 * 獲得EVENT的上下文
	 * 
	 * @return
	 */
	public static Context getEventContext() {
		if (eventContext.get() == null) {
			eventContext.set(new EventContext());
		}
		return eventContext.get();
	}

	/**
	 * 獲得SESSION的上下文
	 * 
	 * @return
	 */
	public static Context getSessionContext() {
		GUID key = getSessionID();
		if (key == null) {
			/*if(log.isDebugEnabled())
			{
				log.debug("getSessionContext error! key is null!");
			}*/
			return null;
		}
		SessionContext context = sessionContexts.get(key);
		if (context == null) {
			if(log.isDebugEnabled())
			{
				log.debug("getSessionContext error! SessionContextis null! key:" + key);
			}
		}
		return context;
	}

	/**
	 * 獲得APPLICATION的上下文
	 * 
	 * @return
	 */
	public static Context getApplicationContext() {
		return applicationContext;
	}

	/**
	 * 獲得User的上下文
	 * 
	 * @return
	 */
//	public static Context getUserContext() {
//		String key = getUserID();
//		if (key == null) {
//			return null;
//		}
//		return userContexts.get(key);
//	}

//	/**
//	 * 獲得CONVERSION的上下文
//	 * 
//	 * @return
//	 */
//	public static Context getGroupContext() {
//		return groupContext;
//	}

	/**
	 * EVENT上下文是否存在
	 * 
	 * @return
	 */
	public static boolean isEventContextActive() {
		return eventContext.get() != null;
	}

	/**
	 * Session上下文是否存在
	 * 
	 * @return
	 */
	public static boolean isSessionContextActive() {
		return getSessionContext() != null;
	}

	/**
	 * Application上下文是否存在
	 * 
	 * @return
	 */
	public static boolean isApplicationContextActive() {
		return getApplicationContext() != null;
	}

//	/**
//	 * User上下文是否存在
//	 * 
//	 * @return
//	 */
//	public static boolean isUserContextActive() {
//		return getUserContext() != null;
//	}

//	/**
//	 * User上下文是否存在
//	 * 
//	 * @return
//	 */
//	public static boolean isGroupContextActive() {
//		return getGroupContext() != null;
//	}

	/**
	 * Remove the named component from all contexts.
	 */
	public static void removeFromAllContexts(String name) {
		if (log.isDebugEnabled()) {
			log.debug("removing from all contexts: " + name);
		}
		
		if (isEventContextActive()) {
			getEventContext().remove(name);
		}
		
		if (isSessionContextActive()) {
			getSessionContext().remove(name);
		}
		if (isApplicationContextActive()) {
			getApplicationContext().remove(name);
		}
//		if (isUserContextActive()) {
//			getUserContext().remove(name);
//		}
	}
	
	/**
	 * Remove the named component from event contexts.
	 */
	public static void removeFromEventContexts(String name) {
		getEventContext().remove(name);
		
	}
	
	/**
	 * Search for a named attribute in all contexts, in the following order:
	 * method, event, page, conversation, session, business process,
	 * application.
	 * 
	 * @return the first component found, or null
	 */
	public static Object lookupInContexts(String name) {

		if (isEventContextActive()) {
			Object result = getEventContext().get(name);
			if (result != null) {
				// if (log.isDebugEnabled()) {
				// log.debug("found in event context: " + name + "\t result:"
				// + result);
				// }
				return result;
			}
		}

		if (isSessionContextActive()) {
			Object result = getSessionContext().get(name);
			if (result != null) {
				// if (log.isDebugEnabled()) {
				// log.debug("found in session context: " + name
				// + "\t result:" + result);
				// }
				return result;
			}
		}

//		Context userContext = getUserContext();
//		if (userContext != null) {
//			Object result = userContext.get(name);
//			if (result != null) {
//				// if (log.isDebugEnabled()) {
//				// log.debug("found in user context: " + name + "\t  result:"
//				// + result);
//				// }
//				return result;
//			}
//		}

		if (isApplicationContextActive()) {
			Object result = getApplicationContext().get(name);
			if (result != null) {
				// if (log.isDebugEnabled()) {
				// log.debug("found in application context: " + name
				// + "\t result:" + result);
				// }
				return result;
			}
		}

		return null;

	}

	/**
	 * 修改public static Object lookupInContexts(String name)
	 * 修改成可判別有沒有找到物件,原本的method沒找到就回傳null,這樣無法判別是沒找到,還是有找到,但是值是null
	 * @return the first component found, or null or NOT_FOUND
	 */
	public static Object lookupInContexts(String name, boolean notFoundAware) {
		if (isEventContextActive() && getEventContext().isSet(name)) {
			return getEventContext().get(name);
		}

		if (isSessionContextActive() && getSessionContext().isSet(name)) {
			return getSessionContext().get(name);
		}

		if (isApplicationContextActive() && getApplicationContext().isSet(name)) {
			return getApplicationContext().get(name);
		}
		
		if(notFoundAware) {
			return NOT_FOUND;
		} else {
			return null;
		}

	}

	/**
	 * Search for a named attribute in all contexts, in the following order:
	 * method, event, page, conversation, session, business process,
	 * application.
	 * 
	 * @return the first component found, or null
	 */
	private static Object lookupInContextsInEventSessionUser(String name) {

		if (isEventContextActive()) {
			Object result = getEventContext().get(name);
			if (result != null) {
				// if (log.isDebugEnabled()) {
				// log.debug("found in event context: " + name + "\t result:"
				// + result);
				// }
				return result;
			}
		}

//		if (isUserContextActive()) {
//			Object result = getUserContext().get(name);
//			if (result != null) {
//				// if (log.isDebugEnabled()) {
//				// log.debug("found in user context: " + name + "\t result:"
//				// + result);
//				// }
//				return result;
//			}
//		}

		if (isSessionContextActive()) {
			Object result = getSessionContext().get(name);
			if (result != null) {
				// if (log.isDebugEnabled()) {
				// log.debug("found in session context: " + name
				// + "\t result:" + result);
				// }
				return result;
			}
		}

		return null;
	}

	/**
	 * 从指定的上下文中查找数据
	 * 
	 * @param name
	 *            对象名称
	 * @param scopeType
	 *            上下文类型
	 * @return 如果找到，则返回对应的对象；否则返回null
	 */
	public static Object lookupInContext(String name, ScopeType scopeType) {

		Context context = getContext(scopeType);

		// 如果是null，则返回null
		if (context == null) {
			return null;
		}

		return context.get(name);
	}

	/**
	 * 清除context的内容
	 * 
	 * @param type
	 *            context的类型
	 */
	public static void clearContext(ScopeType type) {
		Context context = getContext(type);
		if (context == null) {
			if (log.isDebugEnabled()) {
				log.debug("context " + type + " is not exist");
			}
			return;
		}
		context.clear();
	}

	/**
	 * 删除session的上下文
	 */
	public static void destroySessionContext(CloseType type) {
		GUID key = getSessionID();
		endSessionContext(key, type);
	}

	/**
	 * 删除user的上下文
	 */
//	public static void destroyUserContext() {
//		String key = getUserID();
//		endUserContext(key);
//	}

	/**
	 * 删除EVENT的上下文<br>
	 * 因为这是threadlocal，所以只clear就可以了
	 */
	public static void destroyEventContext() {
		clearContext(ScopeType.EVENT);
	}

	public static Context getContext(ScopeType scopetype) {
		switch (scopetype) {
		case APPLICATION:
			return getApplicationContext();
		case SESSION:
			return getSessionContext();
//		case USER:
//			return getUserContext();
		case EVENT:
			return getEventContext();
//		case GROUP:
//			return getGroupContext();
		}
		return null;
	}

	/**
	 * 获得默认的SessionID
	 * 
	 * @return
	 */
	public static GUID getSessionID() {
		// 如果EVENT的上下文不存在，则返回null
		if (!isEventContextActive()) {
			return null;
		}

		GUID key = (GUID) getEventContext().get(SESSION_ID_KEY);
		return key;
	}

	/**
	 * 获得默认的UserID
	 * 
	 * @return
	 */
	public static GUID getUserID() {

		GUID userID = null;
		// 如果EVENT的上下文不存在，则返回null
		// if (isEventContextActive()) {
		//	userID = (String) getEventContext().get(USER_ID_KEY);
		// }

		if (userID == null) {
			GUID sessionID = getSessionID();
			userID = PlayerCommonInfoManager.getInstance().getPlayerGuidBySession(sessionID);

			// log.info("======= getUserID "+ userID +" "+ sessionID);
		}
		return userID;
	}

	/**
	 * 设置默认的SessionID
	 * 
	 * @return
	 */
	public static void setSessionID(GUID sessionID) {
		getEventContext().set(SESSION_ID_KEY, sessionID);
	}

	/**
	 * 设置默认的UserID
	 * 
	 * @return
	 */
	public static void setUserID(GUID userID) {
		getEventContext().set(USER_ID_KEY, userID);
	}

	public static synchronized void initContext(ScopeType scopetype) {
		
		Context context = getContext(scopetype);
		// 如果没有对应的上下文，则初始给构建
		if (context == null) {
			switch (scopetype) {
			// application
			case APPLICATION:
				throw new IllegalStateException(
						"application context is not active!");

				// user
//			case USER:
//				String userID = getUserID();
//				if (userID == null) {
//					throw new IllegalStateException(
//							"userID is not exist in event context!");
//				}
//				userContexts.put(userID, new UserContext());
//				break;
			// session
			case SESSION:
				GUID sessionID = getSessionID();
				if (sessionID == null) {
					throw new IllegalStateException(
							"sessionID is not exist in event context!");
				}
				sessionContexts.put(sessionID, new SessionContext());
				break;
			// event
			case EVENT:
				throw new IllegalStateException("event context is not active!");
			}

		}
	}

	/**
	 * 对象存放在默认生命周期，即最低生命周期
	 * 
	 * @param name
	 *            对象名称
	 * @param obj
	 *            对象实例
	 */
	public static void putInContexts(String name, Object obj) {
		getEventContext().set(name, obj);
	}

	/**
	 * 对象存放在指定的生命周期
	 * 
	 * @param name
	 *            对象名称
	 * @param obj
	 *            对象实例
	 * @param scopetype
	 *            生命周期
	 */
	public static void putInContexts(String name, Object obj,
			ScopeType scopetype) {
		
		Context context = getContext(scopetype);
		if (context != null) {
			context.set(name, obj);
		} else {
			if(log.isDebugEnabled()){
				log.debug("context is null! ScopeType:" + scopetype + " key:"
						+ name + " value:" + obj);
			}
		}
	}

	/**
	 * 开始User Context
	 * 
	 * @param userID
	 */
//	public static void startUserContext(String userID) {
//		if (userID == null) {
//			throw new IllegalArgumentException(
//					"userID is not exist in event context!");
//		}
//		
//		// event Context添加此数据
//		putUserIDInEventContext(userID);
//
//		String sessionId = getSessionID();
//
//		putUserSessionId(userID, sessionId);
//
//		// 如果User Context没有时，就创建
//		if (userContexts.get(userID) == null) {
//			userContexts.put(userID, new UserContext());
//			if (log.isDebugEnabled()) {
//				log.debug("user context start:" + userID);
//			}
//		}
//		// 否则不处理
//		else {
//			if (log.isDebugEnabled()) {
//				log.debug("user context is already start:" + userID);
//			}
//		}
//		
//		putInContexts(USER_ID_KEY, userID, ScopeType.SESSION);
//		
//		// 登入的時候,這個Method會被call兩次, 所以底下這個在 第二次call的時候才會成功, 在trace的時候不要太意外<br>
//		// 這個問題以後自再說<br>
//		//putInContexts(USER_ID_KEY, userID, ScopeType.USER);
//
//		for (ContextsListener listener : listeners) {
//			listener.startUserContexts(userID, sessionId);
//		}
//
//		log.info("======= start user context:" + userID
//				+ " userAmount:" + userContexts.size());
//
//	}
	
	/**
	 * 开始User Context
	 * 
	 * @param userID
	 */
	public static void synchroUserSessionMessage(GUID userID, GUID sessionID) {
		if (userID == null) {
			throw new IllegalArgumentException(
					"userID is not exist in event context!");
		}
		
		if (sessionID == null) {
			throw new IllegalArgumentException(
			"sessionID is not exist in event context!");
		}
		
		synchroUserSession(userID, sessionID);
		
		//消息广播
		// 发送信息给组成员
		GroupMessage msg = new GroupMessage();
		msg.setMessageType(MessageTypes.USERID_SESSIONID_SYNCHRO);
		ContextStatus status = new ContextStatus();
		status.setUserId(userID);
		status.setSessionId(sessionID);
		msg.setMessageContent(status);
		MessageAction.sendGroupMessage(msg);

	}
	
	/**
	 * 同步sessionID与UserID的数据对应关系
	 * @param userID
	 * @param sessionID 如果sessionID是空，则移除
	 */
	public static void synchroUserSession(GUID userID, GUID sessionID) {
		if (userID == null) {
			throw new IllegalArgumentException(
			"userID is not exist in event context!");
		}
		
		// 如果sessionID不是空，则添加，空则移除
		if(sessionID != null){
			putUserSessionId(userID, sessionID);
		}
		else {
			sessionID = getSessionIdByUserId(userID);
			removeUserSessionId(userID, sessionID);
		}
		

		log.info("synchro userID sessionID: " + userID + " <-> " + sessionID);
		
	}

	/**
	 * 开始User Context
	 * 
	 * @param userID
	 */
//	public static void startUserContext(String userID, String sessionID) {
//		
//		// 這個可能已經沒用了
//		putSessionIDInEventContext(sessionID);
//		
//		// 這個可能已經沒用了		
//		startSessionContext(sessionID);
//		
//		startUserContext(userID);
//
//		// log.info("start user context 2:" + userID + " " + sessionID);
//	}

//	/**
//	 * 开始User Context，并组播消息
//	 * 
//	 * @param userID
//	 */
//	public static void startUserContextMessage(String userID) {
//	
//		startUserContext(userID);
//		
//		String sessionID = getSessionID();
//		//userSessionID.putAsync(userID, sessionID);
//		//userSessionID.putAsync(sessionID, userID);
//		
//		userSessionIDlocal.put(userID, sessionID);
//		userSessionIDlocal.put(sessionID, userID);
//
//		// 组播状态改变消息
//		sendGroupContextMessage(TransportManager.USER_CONTEXT_CHANGE, userID,
//				getSessionID(), ContextStatus.CONTEXT_START, CloseType.NONE);
//	}

	/**
	 * 廣播給所有的 common module
	 * 
	 * @param messageType
	 * @param id
	 * @param contextsStatus
	 * 
	 * @author lipeilin
	 * @2011-3-15 上午10:55:29
	 */
	private static void sendGroupContextMessage(int messageType, GUID userId, GUID sessionId, int contextsStatus,
			CloseType closeType, String gateway, String clientIp, String loginPlatform, String agentData) {
		if (log.isInfoEnabled()) {
			String messageTypeStr = ConstantCode.getName(MessageTypes.class, messageType);
			String contextsStatusStr = ConstantCode.getName(ContextStatus.class, contextsStatus);

			log.info(GameUtility.getCurMethodName() 
					+ "() messageType=" + messageTypeStr
					+ " userId=" + userId
					+ " sessionId=" + sessionId
					+ " contextsStatus=" + contextsStatusStr
					+ " closeType=" + closeType 
					+ " gateway=" + gateway 
					+ " clientIp=" + clientIp 
					+ " loginPlatform=" + loginPlatform
					+ " agentData=" + agentData
			);
		}
		
		// 发送信息给组成员
		GroupMessage msg = new GroupMessage();
		msg.setMessageType(messageType);
		ContextStatus status = new ContextStatus();
		status.setUserId(userId);
		status.setSessionId(sessionId);
		status.setStatus(contextsStatus);
		status.setCloseType(closeType);
		status.setGateway(gateway);
		status.setClientIp(clientIp);
		status.setLoginPlatform(loginPlatform);
		status.setAgentData(agentData);
		msg.setMessageContent(status);
		//一個process一次就好了
		msg.setDestModuleID(ModuleName.COMMON);
		MessageAction.sendGroupMessage(msg);
	}

	/**
	 * 在EventContext内保存userID
	 * 
	 * @param userID
	 */
	public static void putUserIDInEventContext(GUID userID) {

		getEventContext().set(USER_ID_KEY, userID);
	}

	/**
	 * 在EventContext内保存userID
	 * 
	 * @param userID
	 */
	public static void putUserIDInSessionContext(GUID userID) {
		
		getSessionContext().set(USER_ID_KEY, userID);
	}

	/**
	 * 结束User Context
	 * 
	 * @param userID
	 */
//	public static void endUserContext(String userID) {		
//		
//		if (userID == null) {
//			log.error("userID is not exist in event context!");
//			return;
//		}
//		
//		if (userContexts.remove(userID) != null) {
//			removeUserSessionIdLocalData(userID);
//			if (log.isDebugEnabled()) {
//				log.debug("end user context:" + userID);
//			}
//		}
//
//		String sessionId = getSessionID();
//		for (ContextsListener listener : listeners) {
//			listener.endUserContexts(userID, sessionId);
//		}
//		
//		log.info("======= end user context:" + userID
//				+ " userAmount:" + userContexts.size());
//	}

	/**
	 * 结束User Context，并组播消息
	 * 
	 * @param userID
	 */
//	public static void endUserContextMessage(String userID) {
//		//endUserContext(userID);
//		
//		// 组播状态改变消息
//		sendGroupContextMessage(TransportManager.USER_CONTEXT_CHANGE, userID,
//				getSessionID(), ContextStatus.CONTEXT_END, CloseType.NONE);
//	}

	/**
	 * 开始Session Context
	 * 
	 * @param sessionID
	 */
	public static void startSessionContext(GUID sessionID) {
		
		if (sessionID == null) {
			throw new IllegalArgumentException(
					"userID is not exist in event context!");
		}		
		
		// event Context添加此数据
		// start session加EventContext 現在已經沒有什麼用處了 !!
		// putSessionIDInEventContext(sessionID);
		

		//if (isSessionContextActive()) {
		//	return;
		//}
		// 如果session Context没有时，就创建
		if (sessionContexts.get(sessionID) == null) {
			sessionContexts.put(sessionID, new SessionContext());
			if (log.isDebugEnabled()) {
				log.debug("session context start:" + sessionID);
			}
		}
		// 否则不处理
		else {
			if (log.isDebugEnabled()) {
				log.debug("session context is already start:" + sessionID);
			}
			return;
		}

		for (ContextsListener listener : listeners) {
			listener.startSessionContexts(sessionID);
		}

		if (ServerProperties.isTargetModule(PlayerCommonInfoManager.getInstance().getGatewayBySessionId(sessionID), ModuleName.H5GATEWAY)) {
			log.info("======= start session context:" + sessionID
					+ " sessionAmount:" + sessionContexts.size() + "/"
					+ H5ServiceInfo.getAllSession().size());
		} else {
			log.info("======= start session context:" + sessionID
					+ " sessionAmount:" + sessionContexts.size() + "/"
					+ ServiceInfo.getAllSession().size());
		}
	}

	/**
	 * 开始Session Context，并组播消息
	 * 
	 * @param userID
	 */
	public static void startSessionContextMessage(GUID sessionID, String gateway, String clientIp,
			String loginPlatform, String agentData) {

		// 這個應該不用做, 可以少call一次 , 還是本地端先call一次, <br>
		// 否則client可能消息速度比建立session還快, 導致有問題<br>
		startSessionContext(sessionID);

		// 接下來通知每個VM 有session被添加到服務器組
		// 也就是說每個vm 都會call一次 startSessionContext()

		// 组播状态改变消息
		sendGroupContextMessage(
				MessageTypes.SESSION_CONTEXT_CHANGE, 
				getUserID(), 
				sessionID,
				ContextStatus.CONTEXT_START, 
				CloseType.NONE, 
				gateway, 
				clientIp, 
				loginPlatform, 
				agentData
		);
	}

	/**
	 * 在EventContext内保存userID
	 * 
	 * @param sessionID
	 */
	public static void putSessionIDInEventContext(GUID sessionID) {		
		getEventContext().set(SESSION_ID_KEY, sessionID);
	}

	/**
	 * 同步sessionID,userID，在Session ,Event ,User Context
	 */
	public static void flushSessionIDUserID() {
		
		// sessionID
		GUID sessionID = (GUID) lookupInContextsInEventSessionUser(SESSION_ID_KEY);
		if (sessionID != null) {
			putInContexts(SESSION_ID_KEY, sessionID, ScopeType.EVENT);
			putInContexts(SESSION_ID_KEY, sessionID, ScopeType.SESSION);
//			if (isUserContextActive()) {
//				putInContexts(SESSION_ID_KEY, sessionID, ScopeType.USER);
//			}
		}

		if (!isSessionContextActive()) {
			// startSessionContext(sessionID);
		}

		GUID userID = getUserID();
		if (userID != null) {
			putInContexts(USER_ID_KEY, userID, ScopeType.EVENT);
			putInContexts(USER_ID_KEY, userID, ScopeType.SESSION);
			//putInContexts(USER_ID_KEY, userID, ScopeType.USER);
		}

		// log.info("======= flushSessionIDUserID:" + userID + " sessionID:" +
		// sessionID);
	}

	/**
	 * 结束Session Context
	 * 
	 * @param sessionID
	 */
	public static void endSessionContext(GUID sessionID, CloseType type) {
		if (sessionID == null) {
			log.error("endSessionContext sessionID is null");
			return;
		}
		
		synchronized (sessionID) {
			for (ContextsListener listener : listeners) {
				listener.endSessionContexts(sessionID, type);
			}
		}


		if (sessionContexts.remove(sessionID) != null) {
			log.info("====== end session context:" + sessionID
					+ " sessionAmount:" + sessionContexts.size());
		}

	}

	/**
	 * 结束Session Context，并组播消息
	 * 
	 * @param userID
	 */
	public static void endSessionContextMessage(GUID sessionID, CloseType closeType) {
		if (log.isInfoEnabled()) {
			log.info(GameUtility.getCurMethodName() + ": sessionID=" + sessionID + " closeType=" + closeType);
		}
		
		//endSessionContext(sessionID);
		GUID playerID= PlayerCommonInfoManager.getInstance().getPlayerGuidBySession(sessionID);

		// 廣播給所有的 common module
		sendGroupContextMessage(MessageTypes.SESSION_CONTEXT_CHANGE, playerID, sessionID,
				ContextStatus.CONTEXT_END, closeType, null, null, null, "");
	}

	/**
	 * 廣播給所有的 module 有 session 關閉了
	 * 
	 * @param sessionId
	 *            session guid
	 * @param closeType
	 *            session close type {@link CloseType}
	 */
	public static void broadcastSessionCloseNotify(GUID sessionId, CloseType closeType, BasicServiceModule operateModule) {
		if (sessionId == null) {
			if (log.isErrorEnabled()) {
				log.error(GameUtility.getCurMethodName() + ": sessionId=null");
			}
			return;
		}

		// 取得角色相關 id
		GUID playerId = null;
		GUID accountId = null;
		String playerName = null;

		playerId = PlayerCommonInfoManager.getInstance().getPlayerGuidBySession(sessionId);
		if (playerId != null) {
			accountId = PlayerCommonInfoManager.getInstance().getAccountIdByPlayerGuid(playerId);
			playerName = PlayerCommonInfoManager.getInstance().getPlayerNameByGuid(playerId);
		}

		// 從 player common 找不到對應的 player id
		if (playerId == null) {
			// 在選角畫面斷線也會找不到 player id
			if (log.isErrorEnabled()) {
				log.error(GameUtility.getCurMethodName()
						+ ": player guid not found in PlayerCommonInfoManager, s=" + sessionId);
			}
		}

		if (log.isInfoEnabled()) {
			log.info(GameUtility.getCurMethodName() + ": send notify s=" + sessionId + " closeType=" + closeType
					+ " accountId=" + accountId + " playerId=" + playerId + " playerName=" + playerName);
		}

		// 填入要送的資料
		SSessionCloseNotify notify = new SSessionCloseNotify();
		notify.setCloseType(closeType);
		notify.setSessionId(sessionId);
		notify.setAccountId(accountId);
		notify.setPlayerId(playerId);
		notify.setPlayerName(playerName);

		// 廣播
		try {
			LoginLogoutListener.broadcastPlayerAndSessionLogOut(notify, operateModule);
		} catch (Exception e) {
			if(log.isErrorEnabled()){
				log.error("can't broadcast session close notify",e);
			}
		}
		
		//2017/05/31 改由指定的module接收
//		GroupMessage msg = new GroupMessage();
//		msg.setMessageType(MessageTypes.S_SESSION_CLOSE_NOTIFY);
//		msg.setMessageContent(notify);
//		MessageAction.sendGroupMessage(msg);
	}
	
//	public static Context getContextFromUser(String userID) {
//		
//		if (userID == null) {
//			return null;
//		}
//		return userContexts.get(userID);
//	}

	public static int getContextSize(ScopeType scopetype) {
		int size = 0;
		switch (scopetype) {
		case APPLICATION:
			size = 1;
			break;
		case EVENT:
			size = 0;
			break;
		case SESSION:
			size = sessionContexts.size();
			break;
//		case USER:
//			size = userContexts.size();
		}
		return size;
	}

	/**
	 * 获得全部的session
	 * 
	 * 
	 * @author lipeilin
	 * @2011-5-11 下午02:14:27
	 */
	public static List<GUID> getAllSession() {
		return new ArrayList<GUID>(sessionContexts.keySet());
	}

	/**
	 * 获得PlayerId对应的SessionId
	 */
	public static GUID getSessionIdByUserId(GUID userId) {
		GUID sessionID = userSessionId.get(userId);
		return sessionID;
	}
	
	/**
	 * 获得SessionId对应的PlayerId
	 */
	public static GUID getUserIdBySessionId(GUID sessionId) {
		
		GUID userId = sessionUserId.get(sessionId);
		return userId;
	}

	/**
	 * 放入userId與sessionId對應表
	 * 
	 */
	private static void putUserSessionId(GUID userId, GUID sessionId) {
		userSessionId.put(userId, sessionId);
		sessionUserId.put(sessionId, userId);
	}

	/**
	 * 删除userId與sessionId對應表
	 * 
	 */
	public static void removeUserSessionId(GUID userID, GUID sessionID) {
		userSessionId.remove(userID);
		sessionUserId.remove(sessionID);
	}
	
	/**
	 * 删除SessionId对应的PlayerId
	 * 
	 * @param sessionGuid
	 * @return
	 * 
	 */
	@Deprecated
	public static void removeUserSessionIdShareData(GUID userId) {
		// String sessionId = getSessionIdByUserId(userId);
		//userSessionID.removeAsync(userId);
		//userSessionID.removeAsync(sessionId);
	}

	/**
	 * 添加监听器
	 * 
	 * @param listener
	 * 
	 * @author lipeilin
	 * @2011-6-20 下午07:47:51
	 */
	public static void addContextsListener(ContextsListener listener) {
		listeners.add(listener);
	}

	/**
	 * 添加监听器
	 * 
	 * @param listener
	 * 
	 * @author lipeilin
	 * @2011-6-20 下午07:47:51
	 */
	public static void removeContextsListener(ContextsListener listener) {
		listeners.remove(listener);
	}
	
	/**
	 * 
	 * @param id
	 * @return
	 */
	public static SessionContext getSessionContextsBySessionID(GUID id){
		return sessionContexts.get(id);
	}
	
	/**
	 * 
	 * @param userID
	 * @return
	 */
//	public static UserContext getUserContextsByUserID(String userID){
//		return userContexts.get(userID);
//	}
	
	
	
	
	
}
